using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net.Security;
using System.Threading;
using System.IO;
using Queues;
using System.Security.Cryptography.X509Certificates;
using System.Collections;
using System.Security.Authentication;

using CyberOPCSpecification;
using Jayrock.Json.Conversion;
using Jayrock.Json;

namespace CyberOPCClient
{
    public class CyberOPCClient
    {

        #region CyberOPC Client Variables
        
        private Hashtable certificateErrors = new Hashtable();
        // CyberOPC Packet Consumer thread.
        private Thread threadConsumer;			
        private BlockingQueue inQ;
        private bool EndConsumer;
        #endregion

        #region CyberOPC Data Structure

        public class CyberOPCItem
        {
           public string CyberOPCItemID;

            public string CyberOPCValue;

            public string CyberOPCTimeStamp;

            public CyberOPCItem(string CyberOPCItemID, string CyberOPCValue, string CyberOPCTimeStamp)
            {
                this.CyberOPCItemID = CyberOPCItemID;
                this.CyberOPCValue = CyberOPCValue;
                this.CyberOPCTimeStamp = CyberOPCTimeStamp;
            }
        }
              
        #endregion

        #region Properties

        private string _machineName = "CYBEROPCGW";// Default value OR Host
        private string _UserAgent = "CyberOPC Client Library";// Default value OR Host
        private string _certificateName = "CYBEROPCGW";// Default value
        private string _LogFile = string.Empty;// Default value
        private string _HttpMethod = "POST";// Default value
        private int _port =8080; // Default value
        private bool _IsConnected = false; // Default value
        private bool CloseStream;
        private int _bufferSize = 5000;
        
        public int BufferCount
        {
            get
            {
                return inQ.Count;
            }
        }
        
        public int BufferSize
        {
            get
            {
                return _bufferSize;
            }
            set
            {
                _bufferSize = value;
            }
        }
        public string machineName
        {
            get
            {
                return _machineName;
            }
            set
            {
                _machineName = value;
            }
        }

        public string UserAgent
        {
            get
            {
                return _UserAgent;
            }
            set
            {
                _UserAgent = value;
            }
        }

        public string HttpMethod
        {
            get
            {
                return _HttpMethod;
            }
            set
            {
                _HttpMethod = value;
            }
        }
     
        public string LogFile
        {
            get
            {
                return _LogFile;
            }
            set
            {
                _LogFile = value;
            }
        }

        public string certificateName
        {
            get
            {
                return _certificateName;
            }
            set
            {
                _certificateName = value;
            }
        }

        public int port
        {
            get
            {
                return _port;
            }
            set
            {
                _port = value;
            }
        }

        public bool IsConnected
        {
            get
            {
                return _IsConnected;
            }
        }

                
        #endregion

        #region Constructors
        /// <summary>
        /// Empty constructors
        /// </summary>
        public CyberOPCClient()
        { }
        /// <summary>
        /// Extended Constructors
        /// </summary>
        /// <param name="machineName"></param>
        /// <param name="port"></param>
        /// <param name="certificateName"></param>
        public CyberOPCClient(string machineName, int port, string certificateName)
        {
            this._machineName = machineName;
            this._port = port;
            this._certificateName = certificateName;
         
        }

        #endregion

        #region Envents-Delegates Data Structure
        public delegate void DataChangeEventHandler(Object sender, DataChangeEventArgs e);

        public event DataChangeEventHandler DataChange;

        public class DataChangeEventArgs : EventArgs
        {
            public ReadResponse.RItem[] _ItemsChanged;

            public DataChangeEventArgs(ReadResponse.RItem[] ItemsChanged)
            {
                this._ItemsChanged  = ItemsChanged;
            }
        }

        public void SendDataChange(ReadResponse.RItem[] ItemsChanged)
        {
            if (DataChange != null)
                DataChange(null, new DataChangeEventArgs(ItemsChanged));
        }
        // Log Status
        public delegate void LogEventHandler(Object sender, LogEventArgs e);

        public event LogEventHandler LogChange;

        public class LogEventArgs : EventArgs
        {
           public string _Logline;
           
            public LogEventArgs(string Logline)
            {
                this._Logline = Logline;
            }
        }

        public void SendLogChange(string Logline)
        {
            if (LogChange != null)
                LogChange(null, new LogEventArgs(Logline));
        }

        #endregion

        #region Public Methods

        
        public void StartStream(int serverhandle, decimal deadband, int waittime)
        {
            string[] parameters = new string[3];
            parameters[0] = serverhandle.ToString();
            if ((deadband < (0.0m)) || (deadband > (1.0m)))
                    throw new Exception("Deadband value out of range(0.0 - 1.0)");
                else
                    parameters[1] = deadband.ToString("0.00").Replace(",",".");
            parameters[2] = waittime.ToString();
            //string cmdstr = this.BuildRequest("StreamStart", parameters);
            //string response = this.SendRequest(cmdstr);
            this.CloseStream = false;
            Thread threadRunClient = new Thread(new ParameterizedThreadStart(RunClientStream));// should be passed the handle here
            threadRunClient.IsBackground = true;//OK
            threadRunClient.Start(parameters);
        }

        public string StopStream(int serverhandle)
        {
            string cmdstr = this.BuildRequest("StreamStop", serverhandle);
            string response = this.SendRequest(cmdstr);
            string result="0";
            JsonObject jresponse = (JsonObject)JsonConvert.Import(response);
            try
            {
                JsonObject jresult = (JsonObject)jresponse["result"];
                JsonNumber jhandle = (JsonNumber)jresult["serverhandle"];
                result = jhandle.ToString();
            }
            catch (Jayrock.Json.JsonException ex)
            {
                throw ex;
            }
            this.CloseStream = true;
            return result;         
        }

        public GetStatusResponse GetStatus()
        {
              GetStatusResponse myObject = null;
              string cmdstr = this.BuildRequest("GetStatus",null);
              string response = this.SendRequest(cmdstr);
              JsonObject jresponse = (JsonObject)JsonConvert.Import(response); 
              try
              {
                  JsonObject jresult = (JsonObject)jresponse["result"];
                  JsonObject jgresult = (JsonObject)jresult["getstatusresult"];
                  JsonObject jginfo = (JsonObject)jresult["statusinfo"];
                  GetStatusResponse.GetStatusResult getstatusresult = (GetStatusResponse.GetStatusResult)JsonConvert.Import(typeof(GetStatusResponse.GetStatusResult), jgresult.ToString() );
                  GetStatusResponse.StatusInfo statusinfo = (GetStatusResponse.StatusInfo)JsonConvert.Import(typeof(GetStatusResponse.StatusInfo), jginfo.ToString() );
                  myObject = new GetStatusResponse(getstatusresult, statusinfo, "");
              }
              catch (Jayrock.Json.JsonException ex)
              {
                  throw ex;
              }
              return myObject;
        }

        public StreamSubscriptionResponse StreamSubscriptionRequest (StreamSubscriptionRequest streamsubscriptionrequest)
        {
            StreamSubscriptionResponse myObject = null;
            string cmdstr = this.BuildRequest("StreamSubscriptionRequest", streamsubscriptionrequest.ItemList);
            string response = this.SendRequest(cmdstr);
            JsonObject jresponse = (JsonObject)JsonConvert.Import(response);
            try
            {
                JsonObject jresult = (JsonObject)jresponse["result"];
                JsonObject jstreamresult = (JsonObject)jresult["streamresult"];
                JsonArray jilist = (JsonArray)jresult["itemlist"];
                JsonNumber jserverhandle = (JsonNumber)jresult["serverhandle"];
                StreamSubscriptionResponse.StreamResult streamresult = (StreamSubscriptionResponse.StreamResult)JsonConvert.Import(typeof(StreamSubscriptionResponse.StreamResult), jstreamresult.ToString());
                string[] ilist = (string[])JsonConvert.Import(typeof(string[]), jilist.ToString());
                int serverhandle = (int)JsonConvert.Import(typeof(int), jserverhandle.ToString());
                myObject = new StreamSubscriptionResponse(streamresult, ilist, serverhandle);
            }
            catch (Jayrock.Json.JsonException ex)
            {
                throw ex;
            }
            return myObject;
        }

        public StreamCancelResponse StreamSubscriptionCancel(StreamSubscriptionCancel streamsubscriptioncancel)
        {
            StreamCancelResponse myObject = null;
            string cmdstr = this.BuildRequest("StreamSubscriptionCancel", streamsubscriptioncancel.ServerHandle);
            string response = this.SendRequest(cmdstr);
            JsonObject jresponse = (JsonObject)JsonConvert.Import(response);
            try
            {
                JsonObject jresult = (JsonObject)jresponse["result"];
                JsonObject jstreamresult = (JsonObject)jresult["streamresult"];
                JsonNumber jserverhandle = (JsonNumber)jresult["serverhandle"];
                StreamCancelResponse.StreamResult streamresult = (StreamCancelResponse.StreamResult)JsonConvert.Import(typeof(StreamCancelResponse.StreamResult), jstreamresult.ToString());
                int serverhandle = (int)JsonConvert.Import(typeof(int), jserverhandle.ToString());
                myObject = new StreamCancelResponse(streamresult, serverhandle);
            }
            catch (Jayrock.Json.JsonException ex)
            {
                throw ex;
            }
            return myObject;
        }


        public ReadResponse Read(ReadRequest readrequest)
        {
            ReadResponse myObject = null;
            string cmdstr = this.BuildRequest("Read", readrequest.ItemList);
            string response = this.SendRequest(cmdstr);
            JsonObject jresponse = (JsonObject)JsonConvert.Import(response);
            try
            {
                JsonObject jresult = (JsonObject)jresponse["result"];
                JsonObject jreadresult = (JsonObject)jresult["readresult"];
                JsonArray jritemlist = (JsonArray)jresult["ritemlist"];
                ReadResponse.ReadResult readresult = (ReadResponse.ReadResult)JsonConvert.Import(typeof(ReadResponse.ReadResult), jreadresult.ToString());
                ReadResponse.RItem[] ritemlist = (ReadResponse.RItem[])JsonConvert.Import(typeof(ReadResponse.RItem[]), jritemlist.ToString());
                myObject = new ReadResponse(readresult,ritemlist);
            }
            catch (Jayrock.Json.JsonException ex)
            {
                throw ex;
            }
            return myObject;
        }

        public ReadEDDResponse ReadEDD(ReadEDDRequest readeddrequest)
        {
            ReadEDDResponse myObject = null;
            string cmdstr = this.BuildRequest("ReadEDD", readeddrequest);
            string response = this.SendRequest(cmdstr);
            JsonObject jresponse = (JsonObject)JsonConvert.Import(response);
            try
            {
                JsonObject jresult = (JsonObject)jresponse["result"];
                JsonObject jreadresult = (JsonObject)jresult["readresult"];
                string jeddfilename = jresult["eddfilename"].ToString();
                string jeddfileurl =  jresult["eddfileurl"].ToString();
                ReadEDDResponse.ReadResult readresult = (ReadEDDResponse.ReadResult)JsonConvert.Import(typeof(ReadEDDResponse.ReadResult), jreadresult.ToString());
                myObject = new ReadEDDResponse(readresult,jeddfilename.ToString(), jeddfileurl.ToString());
            }
            catch (Jayrock.Json.JsonException ex)
            {
                throw ex;
            }
            return myObject;
        }

        public ReadEDDTableResponse ReadEDDTable()
        {
            ReadEDDTableResponse myObject = null;
            string cmdstr = this.BuildRequest("ReadEDDTable", null);
            string response = this.SendRequest(cmdstr);
            JsonObject jresponse = (JsonObject)JsonConvert.Import(response);
            try
            {
                JsonObject jresult = (JsonObject)jresponse["result"];
                JsonObject jreadresult = (JsonObject)jresult["readresult"];
                JsonObject jeddtable = (JsonObject)jresult["eddtable"];
                Dictionary<string, string> eddtable = new Dictionary<string, string>(); 
                //foreach(JsonObject j in jeddtable)
                //    eddtable.Add(j.   TODO
                eddtable = (Dictionary<string,string>)JsonConvert.Import(typeof(Dictionary<string,string>), jeddtable.ToString());
                ReadEDDTableResponse.ReadResult readresult = (ReadEDDTableResponse.ReadResult)JsonConvert.Import(typeof(ReadEDDTableResponse.ReadResult), jreadresult.ToString());
                myObject = new ReadEDDTableResponse(readresult,eddtable);
            }
            catch (Jayrock.Json.JsonException ex)
            {
                throw ex;
            }
            return myObject;
        }
        //public WriteResponse Write(WItemList wilist)
        //{ 
        
        //}

        //public BrowseResponse Browse(string ipath) { }

        #endregion

        #region Private Methods - Socket SSL
        
        private string SendRequest(string cmdstr)
        {
            TcpClient client = new TcpClient(machineName, port);
            SslStream sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
            SendLogChange("Authenticating client and server...");
            if (!AuthenticatClient(sslStream))
            {
                client.Close();
                throw new Exception("Failed SSL Authentication.");
            }
            else
            {
                SendLogChange("Sending request...");
                string serverMessage = null;
                string serverBodyMessage = null;
                byte[] messsage = Encoding.UTF8.GetBytes(cmdstr);
                sslStream.Write(messsage);
                sslStream.Flush();
                // Read message from the server.
                serverMessage = ReadMessageServerResponse(sslStream);
                serverBodyMessage = serverMessage.Replace("\r\n\r\n","|").Split('|')[1]; 
                client.Close();
                sslStream.Close();//*****test
                return serverBodyMessage;
            }
        }

        private bool AuthenticatClient(SslStream sslStream)
        {
            try
            {
                sslStream.AuthenticateAsClient(this.certificateName);
            }
            catch (AuthenticationException e)
            {
                SendLogChange("Exception: " + e.Message);
                if (e.InnerException != null)
                {
                    SendLogChange("Inner exception: " + e.InnerException.Message);
                }
                SendLogChange("Authentication failed - closing the connection.");
                return false;
            }
            return true;
        }

        private int GetBodyContentLength(string serverheader)
        {
            string[] headertoken = serverheader.Split('\r');
            foreach (string s in headertoken)
            {
                if (s.IndexOf("Content-Length") != 1)
                {
                    return Int32.Parse(s.Split(':')[1]);
                }
            }
            return 2048;//Defalut value
        }

        private string ReadMessageBodyResponse(SslStream sslStream, int len)
        {
            byte[] buffer = new byte[len];
            StringBuilder messageBodyData = new StringBuilder();
            int bytes = -1;
            do
            {
                bytes = sslStream.Read(buffer, 0, buffer.Length);
                Decoder decoder = Encoding.UTF8.GetDecoder();
                char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
                decoder.GetChars(buffer, 0, bytes, chars, 0);
                messageBodyData.Append(chars);
                if (messageBodyData.ToString().IndexOf("\r\n\r\n") != -1)
                {
                    break;
                }
            } while (bytes != 0);
            return messageBodyData.ToString();
        }

        private string ReadMessageServerResponse(SslStream sslStream)
        {
            byte[] buffer = new byte[2048];
            StringBuilder messageHeaderData = new StringBuilder();
            int bytes = -1;
            do
            {
                bytes = sslStream.Read(buffer, 0, buffer.Length);
                Decoder decoder = Encoding.UTF8.GetDecoder();
                char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
                decoder.GetChars(buffer, 0, bytes, chars, 0);
                messageHeaderData.Append(chars);
                if (messageHeaderData.ToString().IndexOf("\r\n\r\n") != -1)
                {
                    break;
                }          
            } while (bytes != 0);
            return messageHeaderData.ToString();
        }

        
        /// <summary>
        /// Connect the Client to the Server over SSL for Streaming
        /// </summary>
        private void RunClientStream(object objparameters)
        {
            string method = "StreamStart";
            string[] Streamparams = (string[])objparameters;
            string parameters = "{ServerHandle:" + Streamparams[0] + ",DeadBand:" + Streamparams[1] + ",WaitTime:" + Streamparams[2] + "}";
            string id = "7";
            // Create a TCP/IP client socket.
            // machineName is the host running the server application.
            TcpClient client = new TcpClient(machineName, port);
            this._IsConnected = true;
            SendLogChange("Client connected for Stream with Handle number " + Streamparams[0] + ".");
            // Create an SSL stream that will close the client's stream.
            SslStream sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
            // The server name must match the name on the server certificate.
            try
            {
                sslStream.AuthenticateAsClient(certificateName);
            }
            catch (AuthenticationException e)
            {
                SendLogChange("Exception: " + e.Message);
                if (e.InnerException != null)
                {
                    SendLogChange("Inner exception: " + e.InnerException.Message);
                }
                SendLogChange("Authentication failed - closing the connection.");
                client.Close();
                return;
            }
            // Encode a  message into a byte array.
            string serverMessage = null;
            //****** "Frame-for-ever" strategy
            // Prepare the streaming request.
            string JSONRPCRequest = EncodeJSONRPCRequest(method, parameters, id);
            byte[] messsage = Encoding.UTF8.GetBytes(JSONRPCRequest);
            sslStream.Write(messsage);
            sslStream.Flush();
            // Initialize the queue
            inQ = new BlockingQueue(_bufferSize);	// Packets to send back to client.
            // Start the CyberOPC Packet ConsumerThread  
            this.EndConsumer = false;
            threadConsumer = new Thread(new ThreadStart(RunConsumer));
            threadConsumer.IsBackground = true;//ok
            threadConsumer.Start();
            bool buffer40 = true;
            // Receive the strem until end streaming message
            do
            {
                // Read message from the server.
                // Each Message is a RItem[] object
                serverMessage = ReadMessage(sslStream);
                // Add serverMessage to the queue
                // Put packet object in inQ for server thread.
                // Server thread will unblock when we put objects into the queue.

                if (serverMessage != "--endstream")
                {
                    inQ.Enqueue(serverMessage);
                }
                if (inQ.Count > (0.95)*inQ.Size)
                {
                    using (TextWriter writer = File.AppendText("t.txt"))
                    {
                        writer.Write(inQ.Count.ToString() + "\n");
                    }
                    SendLogChange("Client stream buffer full! Madatory Empty. ");
                    inQ.Clear();
                    buffer40 = true;
                }
                else if(inQ.Count>((0.89)*inQ.Size))
                {
                    SendLogChange("Client stream buffer 90% full! ");
                    buffer40 = false;
                }
                else if (inQ.Count > ((0.79) * inQ.Size))
                {
                    SendLogChange("Client stream buffer 80% full! ");
                    buffer40 = false;
                }
                else if (inQ.Count > ((0.69) * inQ.Size))
                {
                    SendLogChange("Client stream buffer 70% full! ");
                    buffer40 = false;
                }
                else if (inQ.Count > ((0.49) * inQ.Size))
                {
                    SendLogChange("Client stream buffer 50% full! ");
                    buffer40 = false;
                }
                else if (inQ.Count < ((0.40) * inQ.Size)&!buffer40)
                {
                    SendLogChange("Client stream buffer under 40% full! ");
                    buffer40 = true;
                }
            } while ((serverMessage != "--endstream") & (this.CloseStream == false));
            this.EndConsumer = true;
            // Close the client connection.
            client.Close();
            sslStream.Close();
            this._IsConnected = false;
            SendLogChange("Client stream closed.");
        }
        /// <summary>
        /// Read the CyberOPC Packet over the SSL Stream
        /// </summary>
        /// <param name="sslStream"></param>
        /// <returns></returns>
        private string ReadMessage(SslStream sslStream)
        {
            // Read the  message sent by the server.
            byte[] buffer = new byte[2048];//*** FOR CLIENT THIS VALUE HAVE TO BE THE MAX XML FILE SIZE
            StringBuilder messageData = new StringBuilder();
            int bytes = -1;
            do
            {
                bytes = sslStream.Read(buffer, 0, buffer.Length);
                // Use Decoder class to convert from bytes to UTF8
                // in case a character spans two buffers.
                Decoder decoder = Encoding.UTF8.GetDecoder();
                char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
                decoder.GetChars(buffer, 0, bytes, chars, 0);
                messageData.Append(chars);
                // Check for CyberOPC Packet End/Start Tag>.
                if (messageData.ToString().IndexOf("--cyberopcpacket") != -1)
                {
                    break;
                }
                // Check for CyberOPC Stream End Tag
                if (messageData.ToString().IndexOf("--endstream") != -1)
                {
                    return "--endstream";//but could lost the last packet
                }
            } while (bytes != 0);
            return messageData.ToString().Replace("--cyberopcpacket", "");
        }

        private string ItemArrayToCommaDelimitedString(ReadResponse.RItem[] rItem, bool AddClientTimeStamp)
        {
            string CommaDelimitedString="";
            if (AddClientTimeStamp)
            {
                for (int i = 0; i < rItem.Length; i++)
                {
                    CommaDelimitedString += "ClientTimestamp," + DateTime.Now.Ticks.ToString() + "," + rItem[i].ItemID + "," + rItem[i].Value.Replace(',','.') + "," + rItem[i].Timestamp + "\n";
                } 
            }
            else
            {
                for (int i = 0; i < rItem.Length; i++)
                {
                    CommaDelimitedString += rItem[i].ItemID + "," + rItem[i].Value.Replace(',', '.') + "," + rItem[i].Timestamp + "\n";
                }            
            }
            return CommaDelimitedString;
        }

        private ReadResponse.RItem[] JsonStringToItemArray(string jtext)
        {
            JsonArray jresponse = (JsonArray)JsonConvert.Import(jtext);
            ReadResponse.RItem[] rItem = (ReadResponse.RItem[])JsonConvert.Import(typeof(ReadResponse.RItem[]), jresponse.ToString()); 
            return rItem;
        }
       
        /// <summary>
       /// CyberOPC Client Consumer
       /// </summary>
        private void RunConsumer()
        {
            // Thread will block waiting on packets and block on queue if full.
            object outObj;
            ReadResponse.RItem[] rItem = null;
            int tried = 0;
            while (!EndConsumer)
            {
                if (!inQ.TryDequeue(out outObj))
                    continue;
                if (outObj != null)
                {
                    rItem = JsonStringToItemArray(outObj.ToString());
                }
                if (LogFile.Length == 0)
                {
                    SendDataChange(rItem);
                }
                else
                {
                    try
                    {
                        using (TextWriter writer = File.AppendText(LogFile))
                        {
                            writer.Write(ItemArrayToCommaDelimitedString(rItem, true));
                        }
                        tried = 0;
                    }
                    catch (Exception ex)
                    {
                        if (tried < 4)
                        {
                            System.Threading.Thread.Sleep(1500);
                            tried++;
                        }
                        else throw ex;
                    }
                }
                outObj = null;
                rItem = null;
            }
            inQ.Clear();
            SendLogChange("Listener Stopped...");
        }

        #endregion
        /// <summary>
        /// NOTE: HTTP Request with GET
        // RequestGET = MakeHeader + http://<end point>?method=<method>&params=<params>
        // Encoding Steps:
        //  Base 64 param value
        //  URL Encoded Base 64 param value
        //  Pre-Encoded Params:
        //  http://<end point>?method=sum&params={"a":3,"b":4}&id=2
        //  http://<end point>?method=sum&params=[3,4]&id=1
        //  Encoded Request:
        //  http://<end point>?method=sum&params=eyJhIjozLCJiIjo0fQ%3D%3D&id=2
        //  http://<end point>?method=sum&params=WzMsNF0%3D&id=1
        //  NOTE: http://groups.google.com/group/json-rpc/web/json-rpc-over-http?pli=1
        /// </summary>
        /// <param name="RPCmethod"></param>
        /// <param name="RPCparams"></param>
        /// <param name="HttpMethod"></param>
        /// <returns></returns>
        private string BuildRequest(string RPCmethod, object RPCparams)
        {
            string method = null;
            string parameters = null;
            string id = null;
            #region NOTE: Import/Export JSON
            // NOTE: Import/Export JSON http://groups.google.com/group/jayrock/web/import-export-json-data
            // Or into a String :
            //StringBuilder sb = new StringBuilder(); 
            //JsonConvert.Export( myObject, sb);
            //or
            //  String s = JsonConvert.ExportToString( myObjet );
            #endregion
            switch (RPCmethod)
            {
                case "GetStatus":
                    method = "GetStatus";
                    parameters = "null";
                    id = "1";
                    break;
                case "Browse":
                    method = "Browse";
                    parameters = (string)RPCparams;
                    id = "2";
                    break;
                case "Read":
                    method = "Read";
                    string ilistarray = JsonConvert.ExportToString(RPCparams);
                    parameters = "{ItemList:"+ ilistarray  +"}";
                    id = "3";
                    break;
                case "Write":
                    method = "Write";
                    parameters = ((WItemList[])RPCparams).ToString();
                    id = "4";  
                    break;
                case "ReadEDD":
                    method = "ReadEDD";
                    ReadEDDRequest ReadEDDRequest = (ReadEDDRequest)JsonConvert.Import(typeof(ReadEDDRequest), JsonConvert.ExportToString(RPCparams));
                    parameters = "{ModuleName:" + ReadEDDRequest.ModuleName + ",DeviceID:"+ReadEDDRequest.DeviceID+"}";
                    id = "11";
                    break;
                case "ReadEDDTable":
                    method = "ReadEDDTable";
                    parameters = "null";
                    id = "12";
                    break;
                case "StreamSubscriptionRequest":
                    method = "StreamSubscriptionRequest";
                    string ilistarraySub = JsonConvert.ExportToString(RPCparams);
                    parameters = "{ItemList:" + ilistarraySub + "}";
                    id = "5";
                    break;
                case "StreamSubscriptionCancel":
                    method = "StreamSubscriptionCancel";
                    string strServerHandle = RPCparams.ToString();
                    parameters = "{ServerHandle:" + strServerHandle + "}";
                    id = "6";
                    break;
                //case "StreamStart":
                //    method = "StreamStart";
                //    string[] Streamparams = (string[])RPCparams;
                //    parameters = "{ServerHandle:" + Streamparams[0] + ",DeadBand:" + Streamparams[1] + ",WaitTime:" + Streamparams[2] + "}";
                //    id = "7";
                //    break;
                case "StreamStop":
                    method = "StreamStop";
                    string SrvHandleStreamStopParam = RPCparams.ToString();
                    parameters = "{ServerHandle:" + SrvHandleStreamStopParam + "}";
                    id = "7";
                    break;

            }
            return EncodeJSONRPCRequest( method, parameters, id);
           
        }

        private string EncodeJSONRPCRequest(string method, string parameters, string id)
        { 
            StringBuilder RequestStrBld = new StringBuilder();
            if (this.HttpMethod == "POST")
            {
                RequestStrBld.AppendFormat("POST /{0} HTTP/1.1\r", this.machineName);
                RequestStrBld.AppendFormat("User-Agent: {0}\r", this.UserAgent);
                RequestStrBld.AppendFormat("Host: {0}\r", this.machineName);
                RequestStrBld.Append("Accept: application/json\r");
                RequestStrBld.Append("Connection: Keep-Alive\r\n");
                RequestStrBld.Append("\r\n");//CRLR
                //{"method": "test", "params": [], "id": 0}
                RequestStrBld.AppendFormat("{{ \"method\":\"{0}\",\"params\":{1},\"id\":{2} }}\r\n",method,parameters,id);
            }
            else if (this.HttpMethod == "GET")
            {
                #region NOTE JSON-RPC
                //Pre-Encoded Params:
                //http://<end point>?method=sum&params={"a":3,"b":4}&id=2
                //http://<end point>?method=sum&params=[3,4]&id=1
                //Encoded Request:
                //http://<end point>?method=sum&params=eyJhIjozLCJiIjo0fQ%3D%3D&id=2
                //http://<end point>?method=sum&params=WzMsNF0%3D&id=1
                #endregion
                RequestStrBld.AppendFormat("GET ?method={0}&params={1}&id={2} HTTP/1.1\r", method, System.Web.HttpUtility.UrlEncode(Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(parameters))), id);
                RequestStrBld.AppendFormat("User-Agent: {0}\r", this.UserAgent);
                RequestStrBld.AppendFormat("Host: {0}\r", this.machineName);
                RequestStrBld.Append("Accept: application/json\r");
                RequestStrBld.Append("\r\n\r\n");//CRLR
            }
            return RequestStrBld.ToString();
        }


        #region SSL Validation
        // The following method is invoked by the RemoteCertificateValidationDelegate.
        private bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            if (sslPolicyErrors == SslPolicyErrors.None)
                return true;

            SendLogChange("Certificate error: "+ sslPolicyErrors);

            // Do not allow this client to communicate with unauthenticated servers.
            return false;
        }
        #endregion

        #region Deserialize (TXT,JSON,XML) to ItemList

        /// <summary>
        /// Deserialize the CyberOPC Packet - TXT Version and stuff an ItemList
        /// [ClientTicks:633453506578906250]--cyberopcpacket
        /// absoluteX;0;633453506473593750
        /// absoluteY;0;633453506474218750
        /// absoluteZ;0;633453506474218750
        /// RPM;0;633453506474218750
        /// Load;0;633453506474218750
        /// --cyberopcpacket
        /// </summary>
        /// <param name="pkt"></param>
        /// <returns></returns>
        private List<CyberOPCItem> DeserializeTXTCyberOPCPacketToItemList(string pkt)
        {
          List<CyberOPCItem> ItemList = new List<CyberOPCItem>();
          // Remove the ticks
          string pdu = pkt.Split(']')[1];
          // Get the Data inside the delimiter --cyberopcpacket
          pkt = pdu.Replace("--cyberopcpacket", "");
          
          //string line = pdu. //readline
          string[] ItemsArray = pkt.Split('\n');
          foreach (string ItemLine in ItemsArray)
          {
              string[] Item = ItemLine.Split(';');
              if (Item[0].Length != 0)
              {
                  ItemList.Add(new CyberOPCItem(Item[0], Item[1], Item[2].Remove(Item[2].Length-1)));
              }
          };
          return ItemList;
        }

        #endregion

    }

}
